#ifndef COMMON_H
#define COMMON_H

#include <QGuiApplication>
#include <QList>
#include <QScreen>
#include <QDebug>
#include <QMap>
#include <QDir>
#include <QUuid>
#ifdef _WIN32
#include <windows.h>
#endif
#include <unistd.h>
#include <QHostAddress>
#include <QAbstractSocket>
#include <QNetworkInterface>
#include <QNetworkAddressEntry>

#ifndef __linux__
#include "newdialog.h"
#include "mydatabase.h"
#endif
#include <QStyledItemDelegate>
#include <QPainter>
#include <QVector>
#include <QMap>

#define lo_ip            "127.0.0.1"
#define lo_port          12366
#define RES              "/res"
#define IMG_PATH         "img/"
#define XML_PATH         "xml/"

#define PTAH_LEN            128

#define DEFAULTVAL              -1
#define ZERO                    0
#define DIRECTION_NUM           8
#define INVALID_NUM             -1
#define RESOURSE_LABEL_WIDTH    500
#define RESOURSE_LABEL_HEIGHT   100

#define StationNameConfigFile "station_name.ini"
#define StyleConfigFile "style.ini"
#define KEY_VALUE "key_value"
#define DEFAULT_MS_PER_PX 80  //滚动字幕默认80毫秒1像素

extern bool g_debug_flag;
extern bool g_run_python;

#define LOG_PRINTF(format, ...) \
do { \
    if (g_debug_flag) \
        fprintf(stderr, "[ %s %s %d ] " format, __func__, __FILE__, __LINE__, ##__VA_ARGS__); \
} while (0)

#define LOG_QDEBUG if (g_debug_flag) qDebug() << "[" << __func__ << __FILE__ << __LINE__ << "]"  \

enum ProjectType
{
  DRM = 0,
  LCD,
};

enum ShowIndex
{
    IndexNegative = -1,
    IndexZERO     = 0,
    IndexOne      = 1,
    IndexTwo      = 2,
    IndexThree    = 3,
    IndexFour     = 4,
};

enum Animation
{
    None     = 1,
    LeftRight = 2,
    OpacityEffect = 3,
    Scale = 4,
    TwoFrameScale = 5
};

enum RunDir
{
   UP = 1,
   DOWN = 2,
};

enum LineType
{
    Line = 0,
    U,
};

enum Staggered
{
    All_Up = 0,
    All_Down,
    Odd_Up,
    Even_Up,
};

enum DIRECTION
{
    RUN_UP         = 0x00,
    RUN_DOWN       = 0x01,
    RUN_INVALID    = -1
};

//door_status:开关门状态;
//1： 开
//2： 关
//3: 隔离(故障)
//4: (紧急)解锁
//5: 障碍(有障碍物)
enum DOORSTATUS
{
    DOOR_EMPTY         = 0,
    DOOR_OPEN          = 1,
    DOOR_CLOSE         = 2,
    DOOR_ISOLATION     = 3,
    DOOR_FAULT         = 4,
    DOOR_OBSTACLE      = 5
};

const QString STR_EMPTY = "";

const QString welcomeFlag     = "welcome";
const QString emergencyFlag   = "emergency";

const QString AllFlag         = "all";
const QString IntervalFlag    = "interval";
const QString ArriveFlag      = "arrive";

const QString ArriveAllFlag   = "arriveall";
const QString IntervalAllFlag = "intervalall";

typedef struct AutoLoadPictureData
{
    AutoLoadPictureData()
    {
        pos = QPoint(-1, -1);
        point_width = 0;
        point_height = 0;
        station_width = 0;
        station_height = 0;
        line_width = 0;
        line_height = 0;
    }
    //每个站点根据起始位置往后推移的位置(如果是站名会根据m_staggered调整)
    QPoint pos;

    //根据图片大小获取的各个控件的具体大小
    int point_width;
    int point_height;
    int station_width;
    int station_height;
    int line_width;
    int line_height;
}AutoData;

struct ObjectInfo
{
    QString object_register_name; //反射
    QString object_name;          //组件类型即组件名称
    QString object_path;          // 组件图标路径
    int     width;
    int     height;
};

enum ObjectIndex
{
    SINGLEVIEW = 0,
    DOORVIEW,
    NEXTVIEW,
    NOWVIEW,
    STARTVIEW,
    TERMINALVIEW,
    TEXTVIEW,
    TIMEVIEW,
    TRAINVIEW,
    STATIONWAYVIEW,
    ARRIVEVIEW,
    ETAVIEW,
    STATIONVIEW,
    LINEVIEW,
    POINTVIEW,
    SUBTRACTVIEW,
};

static const ObjectInfo s_object[]=
{
    {"SingleView*",        "SingleView",       "",   50,   50},
    {"DoorView*",          "DoorView",         "",   50,   50},
    {"NextView*",          "NextView",         "",   50,   50},
    {"NowView*",           "NowView",          "",   600,  50},
    {"StartView*",         "StartView",        "",   50,   50},
    {"TerminalView*",      "TerminalView",     "",   50,   50},
    {"TextView*",          "TextView",         "",   100,  100},
    {"TimeView*",          "TimeView",         "",   50,   50},
    {"TrainView*",         "TrainView",        "",   50,   50},
    {"StationwayView*",    "StationwayView",   "",   50,   50},
    {"ArriveView*",        "ArriveView",       "",   50,   50},
    {"EtaView*",           "EtaView",          "",   50,   50},
    {"StationView*",       "StationView",      "",   50,   50},
    {"LineView*",          "LineView",         "",   50,   50},
    {"PointView*",         "PointView",        "",   50,   50},
    {"SubtractView*",      "SubtractView",     "",   50,   50},
};

enum ParamIndex
{
    ParamType = 0,
    ParamRunDir,
};

//差异显示类型
enum DiffShowType
{
    ReShow = 0,//全部重新显示
    DiffShowSuffix,//只是显示加后缀的控件
    DiffShowItemsChange,//只是重新显示itemschange修改的控件
};

enum XmlType
{
    Up = 0,
    UpMirror,
    Down,
    DownMirror
};


typedef struct
{
    int station_num;

    int type;//后面删除
    // 起始点坐标
    int begin_x;
    int begin_y;
    //终点坐标
    int end_x;
    int end_y;
    //站名位置
    int staggerd;
    //站名和点之间相对标准距离的偏移量，可以为负数。标准距离为：(Point.Height + Name.Height) / 2，值越大表示原理点控件中心点
    QPoint name_offset;
}LineInfo;

typedef struct DynamicMapParam
{
    int m_type;

    QString m_project_name;
    QString m_project_path;

    int m_width;
    int m_height;

    bool m_ismultiline;// 是否有多线路

    QMap<int, LineInfo> mLineInfoList;//(包括站点个数，起终点坐标，交错方式)
    QVector<LineInfo> mLineInfoVector;//(包括站点个数，起终点坐标，交错方式)
    int m_station_total;

    bool m_has_mirror;//默认无镜像，为true表示有镜像
    bool m_has_down; //默认是上行, 为true表示有下行
    bool m_has_interval;
    bool m_next_time;  //默认不显示未来到站时间

    int m_unequal_spacing_offset;

    int m_interval_begin_x;
    int m_interval_begin_y;
    int m_interval_end_x;
    int m_interval_end_y;
    int m_interval_station_num;
    int m_interval_cur_station_pos;
    int m_interval_staggered;
    int m_interval_unequal_spacing_offset;
    int m_interval_name_offset;

    //点线名位置以及宽高数据
    AutoData m_station_data;
    AutoData m_interval_station_data;

    QMap<QString, QWidget*> mMapObjectShow;

    QStringList m_pic_not_found_list;

    DynamicMapParam()
    {
        m_type = 0;
        m_project_name = "";
        m_project_path = "";
        mLineInfoList.clear();
        mLineInfoVector.clear();
        m_width = 0;
        m_height = 0;
        m_ismultiline = false;
        m_has_mirror = false;
        m_has_down = false;
        m_has_interval = false;
        m_next_time = false;
        m_interval_station_num = 0;
        m_interval_cur_station_pos = 0;
        m_interval_staggered = 0;
        m_interval_begin_x = 0;
        m_interval_begin_y = 0;
        m_interval_end_x = 0;
        m_interval_end_y = 0;
        m_unequal_spacing_offset = 0;
        m_interval_unequal_spacing_offset = 0;
        m_interval_name_offset = 0;
        m_pic_not_found_list.clear();
        m_station_total = 0;
    }

}*PtrDynamicMapParam;

class Screen
{
public:
    static QSize GetScreenSize() //以获取到的屏幕列表中第一个屏幕分辨率作为返回值
    {
        QList <QScreen*> screen_list = QGuiApplication::screens();
#ifdef _WIN32
        int height = GetSystemMetrics(SM_CYFULLSCREEN);
        QSize size(screen_list.first()->size().width(), height);
        return size;
#else
        return screen_list.first()->size();
#endif

    }

    static quint16 GetScreenWidth()
    {
        QList <QScreen*> screen_list = QGuiApplication::screens();
        return screen_list.first()->size().width();
    }

    static quint16 GetScreenHeight()
    {
        QList <QScreen*> screen_list = QGuiApplication::screens();
#ifdef WIN32
        return GetSystemMetrics(SM_CYFULLSCREEN);
#else
        return screen_list.first()->size().height();
#endif
    }
};

class myapp : public QObject
{
public:

    static bool isFileExist(QString fullFilePath)
    {
        QFileInfo info(fullFilePath);
        return info.isFile();
    }

    static bool isDirExist(QString fullPath)
    {
        QFileInfo info(fullPath);
        return info.isDir();
    }

    static QString getRandomString()
    {
        return  QUuid::createUuid().toString().remove("{").remove("}").remove("-");
    }

    static char* buf_find (const char *haystack, size_t haystack_len, const char *needle)
    {
      const char *search = haystack;
      const char *end = haystack + haystack_len;
      char *p;
      size_t len = strlen (needle);

      while (search < end && (p =  static_cast<char *>(const_cast<void *>(memchr(search, *needle, end - search)))) != NULL)
      {
        if (p + len > end)
          break;
        if (memcmp (p, needle, len) == 0)
          return (p);
        search = p + 1;
      }

      return (NULL);
    }

    static QPoint to_mid(QPoint origin, quint16 w, quint16 h)
    {
        return origin + QPoint(w>>1, h>>1);
    }

    static QPoint to_origin(QPoint mid_point, quint16 w, quint16 h)
    {
        return mid_point - QPoint(w>>1, h>>1);
    }

    /***
      *判断一个字符串是否为纯数字
      */
    static int isDigitStr(QString src)
    {
        QByteArray ba = src.toLatin1();//QString 转换为 char*
         const char *s = ba.data();

        while(*s && *s>='0' && *s<='9') s++;

        if (*s)
        { //不是纯数字
            return 0;
        }
        else
        { //纯数字
            return 1;
        }
    }

    //插入字符
    static void insertStrEveryChar(QString &original, const QString &insert)
    {
        int size = original.size();
        int size_all = size + (size - 1) * insert.size();
        //每隔一个字符插入一个 insert
        for (int i = 1; i < size_all; i = i + insert.size() + 1)
            original.insert(i, insert);
    }

    static QString getQssContentByKey(QString qss, const QString key)
    {
        if (!qss.contains(key))
            return "";

        if (!qss.endsWith(";"))
            qss.append(";");

        int start_index, end_index;

        start_index = qss.indexOf(key) + key.size() + 1;

        end_index = qss.indexOf(";", start_index);

        return qss.mid(start_index, end_index - start_index);
    }

    static QString find_file_single(QString prefix, QString name)
    {
        if (name == "")
            return "";

        QString hqv = QString("%1%2.hqv").arg(prefix).arg(name);
        QString gif = QString("%1%2.gif").arg(prefix).arg(name);
        QString png = QString("%1%2.png").arg(prefix).arg(name);

        if (myapp::isDirExist(hqv))
            return  QString("%1.hqv").arg(name);;

        if (myapp::isFileExist(gif))
            return QString("%1.gif").arg(name);

        if (myapp::isFileExist(png))
            return QString("%1.png").arg(name);

        return "";
    }

    static bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist)
    {
        QDir sourceDir(fromDir);
        QDir targetDir(toDir);

        if (!targetDir.exists())
        {   /**< 如果目标目录不存在，则进行创建 */
            if (!targetDir.mkdir(targetDir.absolutePath()))
                return false;
        }
        QFileInfoList fileInfoList = sourceDir.entryInfoList();
        foreach (QFileInfo fileInfo, fileInfoList)
        {
            if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
                continue;
            if (fileInfo.isDir())
            {   /**< 当为目录时，递归的进行copy */
                if(!copyDirectoryFiles(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()), coverFileIfExist))
                    return false;
            }
            else
            {   /**< 当允许覆盖操作时，将旧文件进行删除操作 */
                if (coverFileIfExist && targetDir.exists(fileInfo.fileName()))
                    targetDir.remove(fileInfo.fileName());
                /// 进行文件copy
                if (!QFile::copy(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName())))
                    return false;
            }
        }
        return true;
    }

    static int getStaggeredFromString(std::string staggered)
    {
        int stag = 0;
        if (staggered == "all_down")
            stag = All_Down;
        else if (staggered == "all_up")
            stag = All_Up;
        else if (staggered == "odd_up")
            stag = Odd_Up;
        else
            stag = Even_Up;
        return stag;
    }

    static QPoint getNameOffsetFromString(std::string offset)
    {
        QString name_offset = QString::fromStdString(offset);

        if (name_offset == "")
            return QPoint(0, 0);

        if (!name_offset.contains(","))
            return QPoint(0, name_offset.toInt());

        if (name_offset.contains("("))
            name_offset.replace("(", "");
        if (name_offset.contains(")"))
            name_offset.replace(")", "");

        QStringList list = name_offset.split(",");
        return QPoint(list.at(0).toInt(), list.at(1).toInt());
    }
    static std::string getNameOffsetFromQPoint(QPoint offset)
    {
        return QString("(%1, %2)").arg(offset.x()).arg(offset.y()).toStdString();
    }
    static std::string getStaggeredFromInt(int staggered)
    {
        std::string stag = "all_up";
        if (staggered == All_Up)
            stag = "all_up";
        else if (staggered == All_Down)
            stag = "all_down";
        else if (staggered == Odd_Up)
            stag = "odd_up";
        else
            stag = "even_up";
        return stag;
    }

    const static int object_num = sizeof (s_object) / sizeof (ObjectInfo);

    static PtrDynamicMapParam mDynamicMapParam;

};

struct emergenry_list
{
    QString id;
    QString text;
};

struct change_property
{
    change_property()
    {
        x = DEFAULTVAL;
        y = DEFAULTVAL;
        w = DEFAULTVAL;
        h = DEFAULTVAL;
        content = "";
    }
    int x;
    int y;
    int w;
    int h;
    QString content;
};


class ProtocolData
{
public:
    ProtocolData()
    {
        ui_type.clear();
        file_path.clear();
        route = "";
        start_id = -1;
        stop_id = -1;
        curr_or_next_id = -1;
        car_number = -1;
        door_status = -1;
        skip_list.clear();
        eta_list.clear();
        emergency_text.clear();
        key_position = 1;
        suffix = "";
        items_change.clear();
    };
    QString suffix;
    QString ui_type;
    QString file_path;
    QString route;
    int  start_id;
    int  stop_id;
    int  curr_or_next_id;
    int  car_number;
    int  door_status;
    int  key_position;
    QVector <int> skip_list;
    QVector <int> eta_list;
    QString scroll_msg;
    QString emergency_img;
    QVector<emergenry_list> emergency_text;
    QMap<QString, change_property> items_change;

    void reset()
    {
        ui_type.clear();
        file_path.clear();
        route = "";
        start_id = -1;
        stop_id = -1;
        curr_or_next_id = -1;
        car_number = -1;
        door_status = -1;
        key_position = 1;
        skip_list.clear();
        eta_list.clear();
        emergency_text.clear();
        suffix = "";
        items_change.clear();
    }
};

#endif // COMMON_H
